package is.ru.honn.rupin.process;

import is.ru.honn.rupin.domain.Board;
import is.ru.honn.rupin.domain.Gender;
import is.ru.honn.rupin.domain.Pin;
import is.ru.honn.rupin.domain.User;
import is.ru.honn.rupin.feeds.FeedEntry;
import is.ru.honn.rupin.feeds.FeedException;
import is.ru.honn.rupin.feeds.FeedHandler;
import is.ru.honn.rupin.feeds.FeedReader;
import is.ru.honn.rupin.service.BoardNotFoundException;
import is.ru.honn.rupin.service.PinService;
import is.ru.honn.rupin.service.UserNotFoundException;
import is.ru.honn.rupin.service.UsernameExistsException;
import is.ruframework.process.RuAbstractProcess;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
/**
 * A process which reads data from an RSS feed and puts into PinService
 *
 * @author Einar Sigurðsson
 * @author Guðni Matthíasson
 * @version 1.0, 19 Oct 2012
 */
public class PinImportProcess extends RuAbstractProcess implements FeedHandler{
    Logger log = Logger.getLogger(this.getClass().getName());
    PinService pinService;
    FeedReader reader;
    MessageSource msg;
    User user;
    Board board;
    int numberofelements = 0;

    /**
     * Initializes the variables needed using dependency injection a la spring framework.
     * Checks whether the user in app.xml exists and if not creates it.
     * Checks whether the board in app.xml exists and if not creates it.
     * Logs process.
     */
    @Override
    public void beforeProcess(){
        ApplicationContext ctx = new FileSystemXmlApplicationContext("src//app.xml");
        pinService = (PinService)ctx.getBean("pinService");
        reader = (FeedReader)ctx.getBean("feedReader");
        reader.setFeedHandler(this);
        msg = (MessageSource)ctx.getBean("messageSource");
        user = (User)ctx.getBean("user");
        board = (Board)ctx.getBean("board");
        log.info(msg.getMessage("processbefore",
                new Object[]{getProcessContext().getProcessName()},
                Locale.getDefault()));
        if(pinService.getUser(user.getUsername()) == null)
            try {
               log.info(msg.getMessage("usernotfound",
                       new Object[]{getProcessContext().getProcessName()},
                       Locale.getDefault()));
               pinService.signUpUser(user.getUsername(), user.getFirstName(), user.getLastName(), user.getEmail(), user.getPassword(), user.getGender());
            } catch (UsernameExistsException e) {
               log.info(msg.getMessage("signupuserfail",
                        new Object[]{getProcessContext().getProcessName()},
                        Locale.getDefault()));
            }
        else
            log.info(msg.getMessage("userexists",
                    new Object[]{getProcessContext().getProcessName()},
                    Locale.getDefault()));
        if(pinService.getBoard(user.getUsername(), board.getName()) == null)
            try {
                log.info(msg.getMessage("boardnotfound",
                        new Object[]{getProcessContext().getProcessName()},
                        Locale.getDefault()));
                pinService.createBoard(user.getUsername(), board.getName(), board.getCategory());
            } catch (UserNotFoundException e) {
                log.info(msg.getMessage("createboardfail",
                        new Object[]{getProcessContext().getProcessName()},
                        Locale.getDefault()));
            }
        else
            log.info(msg.getMessage("boardexists",
                    new Object[]{getProcessContext().getProcessName()},
                    Locale.getDefault()));
    }
    /**
     * Reads data from the RSS feed and puts the data in pins
     * which are inserted on the board retrieved in function beforeProcess
     */
    @Override
    public void startProcess(){
        log.info(msg.getMessage("processstart",
                new Object[] { getProcessContext().getProcessName() },
                Locale.getDefault()));
        try{
            reader.setSource(getProcessContext().getImportURL());
            reader.read();
        }catch (FeedException e){
            log.info(msg.getMessage("processreaderror",
                    new Object[] { getProcessContext().getImportFile() },
                    Locale.getDefault()));
            log.info(e.getMessage());
        }
        log.info(msg.getMessage("processstartdone",
                new Object[]{numberofelements},
                Locale.getDefault()));
    }

    /**
     * Generates an HTML file for visual representation of a board
     * @throws IOException
     */
    private void printHtml() throws IOException{
        List<Pin> pins = pinService.getPinsOnBoard(user.getUsername(), board.getName());

        BufferedReader template = new BufferedReader(new FileReader("template.tmpl"));
        File output = new File("output/output.html");
        PrintWriter pw = new PrintWriter(new FileWriter(output));

        ArrayList<String> tmplLines = new ArrayList<String>();
        String line;
        while((line = template.readLine()) != null){
            tmplLines.add(line);
        }
        template.close();
        Iterator<String> s = tmplLines.iterator();
        while(s.hasNext()){
            line = s.next();
            pw.write(line);
            if(line.equals("<body>")) {
                pw.write("\n<ul>\n");
                for(Pin pin: pins){
                    pw.write("<li>\n<ul>\n\n<li class=\"image\"><img src=\"" + pin.getImage() + "\" alt=\"Rss Image\" /></li>");
                    pw.write("\n<li>\n<p>"+pin.getDescription());
                    pw.write(" <a href=\"" + pin.getLink() + "\"> more here </a></p>\n</li>\n</ul>\n</li>");
                }
                pw.write("\n</ul>\n");
            }
        }
        pw.close();
    }
    /**
     * Calls a function to print an html file at output/output.html
     */
    @Override
    public void afterProcess(){
        try {
            printHtml();
        } catch (IOException e) {
            log.info("couldn't make html file");
        }
        log.info(msg.getMessage("processafter",
                new Object[]{"output/output.html"},
                Locale.getDefault()));


    }
    /**
     * puts the feed entry into a pin and puts the pin onto a board
     */
    @Override
    public void processEntry(FeedEntry entry) {
        try{
        pinService.createPin(user.getUsername(), board.getName(), entry.getLink(), entry.getDescription(), entry.getImage());
        } catch (BoardNotFoundException e) {
            log.info(e.getMessage());
        }
        ++numberofelements;
    }
}
